"""
Coze智能体配置和管理模块
支持bot_id和API密钥管理，豆包·视觉理解·Pro模型配置
"""

import os
import json
import logging
import yaml
from typing import Dict, Any, Optional, List, Tuple
from dataclasses import dataclass, asdict
from pathlib import Path
from cryptography.fernet import Fernet
import base64

logger = logging.getLogger(__name__)


@dataclass
class CozeModelConfig:
    """Coze模型配置"""
    model_name: str = "豆包·视觉理解·Pro"
    model_id: str = "doubao-vision-pro"
    max_tokens: int = 4096
    temperature: float = 0.7
    top_p: float = 0.9
    supports_vision: bool = True
    supports_audio: bool = True
    supports_streaming: bool = True


@dataclass
class CozeAgentConfig:
    """Coze智能体配置"""
    bot_id: str
    bot_name: str = "EchokitBot视觉助手"
    description: str = "专门用于视觉理解和交互的智能助手"
    model_config: CozeModelConfig = None
    system_prompt: str = "你是一个专业的视觉理解助手，能够准确描述图像内容并回答相关问题。"
    max_conversation_turns: int = 10
    timeout_seconds: int = 30
    
    def __post_init__(self):
        if self.model_config is None:
            self.model_config = CozeModelConfig()


@dataclass
class CozeAPICredentials:
    """Coze API凭证"""
    api_key: str
    api_secret: Optional[str] = None
    base_url: str = "https://api.coze.cn"
    api_version: str = "v1"
    
    
@dataclass
class CozeConnectionConfig:
    """Coze连接配置"""
    openapi_enabled: bool = True
    websocket_enabled: bool = True
    websocket_url: str = "wss://api.coze.cn"
    max_retries: int = 3
    retry_delay: float = 1.0
    connection_timeout: int = 30
    request_timeout: int = 60


@dataclass
class CozeFlowConfig:
    """Coze对话流配置"""
    flow_id: Optional[str] = None
    flow_name: str = "视觉理解对话流"
    parameters: Dict[str, Any] = None
    enable_parameter_passing: bool = True
    image_parameter_name: str = "image"
    audio_parameter_name: str = "audio"
    
    def __post_init__(self):
        if self.parameters is None:
            self.parameters = {}


class CozeConfigManager:
    """
    Coze配置管理器
    负责管理API密钥、智能体配置和对话流参数
    """
    
    def __init__(self, config_dir: str = None):
        """
        初始化配置管理器
        
        Args:
            config_dir: 配置文件目录
        """
        if config_dir is None:
            config_dir = os.path.join(os.path.expanduser("~"), ".echokitbot", "coze")
            
        self.config_dir = Path(config_dir)
        self.config_dir.mkdir(parents=True, exist_ok=True)
        
        self.config_file = self.config_dir / "coze_config.yaml"
        self.credentials_file = self.config_dir / "credentials.enc"
        self.agents_file = self.config_dir / "agents.yaml"
        
        self._encryption_key = self._get_or_create_encryption_key()
        self._config_cache: Optional[Dict[str, Any]] = None
        
    def _get_or_create_encryption_key(self) -> bytes:
        """获取或创建加密密钥"""
        key_file = self.config_dir / ".key"
        
        if key_file.exists():
            with open(key_file, 'rb') as f:
                return f.read()
        else:
            key = Fernet.generate_key()
            with open(key_file, 'wb') as f:
                f.write(key)
            # 设置文件权限为仅所有者可读写
            os.chmod(key_file, 0o600)
            return key
            
    def _encrypt_data(self, data: str) -> str:
        """加密数据"""
        fernet = Fernet(self._encryption_key)
        encrypted_data = fernet.encrypt(data.encode())
        return base64.b64encode(encrypted_data).decode()
        
    def _decrypt_data(self, encrypted_data: str) -> str:
        """解密数据"""
        fernet = Fernet(self._encryption_key)
        decoded_data = base64.b64decode(encrypted_data.encode())
        decrypted_data = fernet.decrypt(decoded_data)
        return decrypted_data.decode()
        
    def save_credentials(self, credentials: CozeAPICredentials):
        """
        保存API凭证（加密存储）
        
        Args:
            credentials: API凭证
        """
        try:
            credentials_data = asdict(credentials)
            encrypted_data = self._encrypt_data(json.dumps(credentials_data))
            
            with open(self.credentials_file, 'w') as f:
                f.write(encrypted_data)
                
            # 设置文件权限
            os.chmod(self.credentials_file, 0o600)
            
            logger.info("API凭证已安全保存")
            
        except Exception as e:
            logger.error(f"保存API凭证失败: {e}")
            raise
            
    def load_credentials(self) -> Optional[CozeAPICredentials]:
        """
        加载API凭证
        
        Returns:
            API凭证对象，如果不存在则返回None
        """
        try:
            if not self.credentials_file.exists():
                return None
                
            with open(self.credentials_file, 'r') as f:
                encrypted_data = f.read()
                
            decrypted_data = self._decrypt_data(encrypted_data)
            credentials_data = json.loads(decrypted_data)
            
            return CozeAPICredentials(**credentials_data)
            
        except Exception as e:
            logger.error(f"加载API凭证失败: {e}")
            return None
            
    def save_agent_config(self, agent_config: CozeAgentConfig):
        """
        保存智能体配置
        
        Args:
            agent_config: 智能体配置
        """
        try:
            # 加载现有配置
            agents_data = {}
            if self.agents_file.exists():
                with open(self.agents_file, 'r', encoding='utf-8') as f:
                    agents_data = yaml.safe_load(f) or {}
                    
            # 更新配置
            agents_data[agent_config.bot_id] = asdict(agent_config)
            
            # 保存配置
            with open(self.agents_file, 'w', encoding='utf-8') as f:
                yaml.dump(agents_data, f, default_flow_style=False, allow_unicode=True)
                
            logger.info(f"智能体配置已保存: {agent_config.bot_id}")
            
        except Exception as e:
            logger.error(f"保存智能体配置失败: {e}")
            raise
            
    def load_agent_config(self, bot_id: str) -> Optional[CozeAgentConfig]:
        """
        加载智能体配置
        
        Args:
            bot_id: 智能体ID
            
        Returns:
            智能体配置对象，如果不存在则返回None
        """
        try:
            if not self.agents_file.exists():
                return None
                
            with open(self.agents_file, 'r', encoding='utf-8') as f:
                agents_data = yaml.safe_load(f) or {}
                
            if bot_id not in agents_data:
                return None
                
            agent_data = agents_data[bot_id]
            
            # 处理嵌套的模型配置
            if 'model_config' in agent_data and agent_data['model_config']:
                agent_data['model_config'] = CozeModelConfig(**agent_data['model_config'])
                
            return CozeAgentConfig(**agent_data)
            
        except Exception as e:
            logger.error(f"加载智能体配置失败: {e}")
            return None
            
    def list_agents(self) -> List[str]:
        """
        列出所有已配置的智能体ID
        
        Returns:
            智能体ID列表
        """
        try:
            if not self.agents_file.exists():
                return []
                
            with open(self.agents_file, 'r', encoding='utf-8') as f:
                agents_data = yaml.safe_load(f) or {}
                
            return list(agents_data.keys())
            
        except Exception as e:
            logger.error(f"列出智能体失败: {e}")
            return []
            
    def save_main_config(self, config: Dict[str, Any]):
        """
        保存主配置文件
        
        Args:
            config: 配置数据
        """
        try:
            with open(self.config_file, 'w', encoding='utf-8') as f:
                yaml.dump(config, f, default_flow_style=False, allow_unicode=True)
                
            self._config_cache = config
            logger.info("主配置文件已保存")
            
        except Exception as e:
            logger.error(f"保存主配置文件失败: {e}")
            raise
            
    def load_main_config(self) -> Dict[str, Any]:
        """
        加载主配置文件
        
        Returns:
            配置数据字典
        """
        try:
            if self._config_cache is not None:
                return self._config_cache
                
            if not self.config_file.exists():
                # 创建默认配置
                default_config = self._create_default_config()
                self.save_main_config(default_config)
                return default_config
                
            with open(self.config_file, 'r', encoding='utf-8') as f:
                config = yaml.safe_load(f) or {}
                
            self._config_cache = config
            return config
            
        except Exception as e:
            logger.error(f"加载主配置文件失败: {e}")
            return self._create_default_config()
            
    def _create_default_config(self) -> Dict[str, Any]:
        """创建默认配置"""
        return {
            'connection': asdict(CozeConnectionConfig()),
            'flow': asdict(CozeFlowConfig()),
            'logging': {
                'level': 'INFO',
                'enable_debug': False,
                'log_api_requests': False
            },
            'cache': {
                'enable_response_cache': True,
                'cache_ttl_seconds': 300,
                'max_cache_size': 100
            },
            'security': {
                'validate_ssl': True,
                'api_key_rotation_days': 90,
                'enable_request_signing': False
            }
        }
        
    def get_connection_config(self) -> CozeConnectionConfig:
        """获取连接配置"""
        config = self.load_main_config()
        connection_data = config.get('connection', {})
        return CozeConnectionConfig(**connection_data)
        
    def get_flow_config(self) -> CozeFlowConfig:
        """获取对话流配置"""
        config = self.load_main_config()
        flow_data = config.get('flow', {})
        return CozeFlowConfig(**flow_data)
        
    def update_connection_config(self, connection_config: CozeConnectionConfig):
        """更新连接配置"""
        config = self.load_main_config()
        config['connection'] = asdict(connection_config)
        self.save_main_config(config)
        
    def update_flow_config(self, flow_config: CozeFlowConfig):
        """更新对话流配置"""
        config = self.load_main_config()
        config['flow'] = asdict(flow_config)
        self.save_main_config(config)
        
    def validate_api_key(self, api_key: str) -> bool:
        """
        验证API密钥格式
        
        Args:
            api_key: API密钥
            
        Returns:
            是否有效
        """
        if not api_key or not isinstance(api_key, str):
            return False
            
        # 基本格式检查
        if len(api_key) < 32:
            return False
            
        # 检查是否包含非法字符
        allowed_chars = set('abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.')
        if not set(api_key).issubset(allowed_chars):
            return False
            
        return True
        
    def validate_bot_id(self, bot_id: str) -> bool:
        """
        验证智能体ID格式
        
        Args:
            bot_id: 智能体ID
            
        Returns:
            是否有效
        """
        if not bot_id or not isinstance(bot_id, str):
            return False
            
        # 基本格式检查
        if len(bot_id) < 10:
            return False
            
        return True
        
    def setup_default_agent(self, bot_id: str, api_key: str) -> bool:
        """
        设置默认智能体配置
        
        Args:
            bot_id: 智能体ID
            api_key: API密钥
            
        Returns:
            设置是否成功
        """
        try:
            # 验证参数
            if not self.validate_bot_id(bot_id):
                raise ValueError("无效的智能体ID")
                
            if not self.validate_api_key(api_key):
                raise ValueError("无效的API密钥")
                
            # 保存凭证
            credentials = CozeAPICredentials(api_key=api_key)
            self.save_credentials(credentials)
            
            # 保存智能体配置
            agent_config = CozeAgentConfig(bot_id=bot_id)
            self.save_agent_config(agent_config)
            
            logger.info(f"默认智能体配置已设置: {bot_id}")
            return True
            
        except Exception as e:
            logger.error(f"设置默认智能体配置失败: {e}")
            return False
            
    def get_environment_config(self) -> Dict[str, str]:
        """
        从环境变量获取配置
        
        Returns:
            环境变量配置字典
        """
        return {
            'COZE_API_KEY': os.getenv('COZE_API_KEY', ''),
            'COZE_BOT_ID': os.getenv('COZE_BOT_ID', ''),
            'COZE_BASE_URL': os.getenv('COZE_BASE_URL', 'https://api.coze.cn'),
            'COZE_WEBSOCKET_URL': os.getenv('COZE_WEBSOCKET_URL', 'wss://api.coze.cn'),
            'COZE_FLOW_ID': os.getenv('COZE_FLOW_ID', ''),
        }
        
    def merge_with_environment(self) -> Tuple[Optional[CozeAPICredentials], Optional[CozeAgentConfig]]:
        """
        合并环境变量和配置文件
        
        Returns:
            (凭证对象, 智能体配置对象) 元组
        """
        env_config = self.get_environment_config()
        
        # 加载文件配置
        credentials = self.load_credentials()
        
        # 环境变量优先
        if env_config['COZE_API_KEY']:
            credentials = CozeAPICredentials(
                api_key=env_config['COZE_API_KEY'],
                base_url=env_config['COZE_BASE_URL']
            )
            
        # 智能体配置
        agent_config = None
        if env_config['COZE_BOT_ID']:
            agent_config = CozeAgentConfig(bot_id=env_config['COZE_BOT_ID'])
            
            # 尝试从文件加载更详细的配置
            file_agent_config = self.load_agent_config(env_config['COZE_BOT_ID'])
            if file_agent_config:
                agent_config = file_agent_config
                
        return credentials, agent_config